# -*- encoding: utf-8 -*-
""" 读取物性表

"""
# base library
import csv
import re
import os
import functools

# third party library
import numpy as np
from scipy.spatial import KDTree

# project library
from utils.base_path import get_base_path
from utils.constant import FluidPhaseType, TabParams
from utils.crdlog import log

# 在文件开头添加缓存字典
_tab_cache = {}

class TabLoader:
    """
    热力学模型构建的TAB表数据读取器
    """

    def __init__(self, tab_file: str = None, iscache: bool = True):
        """
        热力学模型构建的TAB表数据读取器的构造函数
        :param tab_file: str, tab物性表文件路径
        :param iscache: bool, 是否使用缓存机制
        :param interp_method: str, 插值方法, 默认双线性插值, 可选idw

        Example:
        # >>> from algorithm.physical_property.tab_loader import TabLoader
        # >>> p = 1e5
        # >>> T = 300
        # >>> rtb = TabLoader(tab_file='tests/tab_data/GXDCASE.tab') # 实例化
        # >>> physical_properties_data = rtb.get_physical_properties_data(p, T)
        # >>> print(rtb._format_dict(physical_properties_data))
        # >>> print(rtb._format_dict(rtb.get_standard_condition_data()))
        # >>> print(rtb.calculate_enthalpy(p, T))
        # >>> print(rtb.is_single_phase_flow())
        # >>> print(rtb.get_phase_type())
        """
        self.tab_file = tab_file
        self.iscache = iscache
        if self.iscache:
            if not self.check_cache():
                self.build_cache()

    def check_cache(self):
        """利用缓存机制读取tab文件和构建KDTree, 防止重复计算"""
        # 检查缓存中是否已存在该文件的数据
        if self.tab_file in _tab_cache:
            log.info(f"读取物性缓存: {self.tab_file}")
            self.points = _tab_cache[self.tab_file]['points']
            self.params_indices_in_tabparams = _tab_cache[self.tab_file]['params_indices_in_tabparams']
            self.standard_condition_data = _tab_cache[self.tab_file]['standard_condition_data']
            # 从缓存读取KDTree
            self.pt_kdtree = _tab_cache[self.tab_file]['pt_kdtree']
            self.physical_properties_array = _tab_cache[self.tab_file]['physical_properties_array']
            self.p_list_tab = _tab_cache[self.tab_file]['p_list_tab']
            self.T_list_tab = _tab_cache[self.tab_file]['T_list_tab']
            return True
        else:
            log.info(f"还未建立物性表缓存")
            return False

    def build_cache(self):
        """构建缓存"""
        log.info(f'读取物性文件:{self.tab_file}')
        self._read_tab()

        # 构建(p,T)插值用的KDTree
        self.p_list_tab = np.unique(self.points[:, 0])
        self.T_list_tab = np.unique(self.points[:, 1])
        scale = np.abs(self.T_list_tab[-1] - self.T_list_tab[0]) / \
            np.abs(self.p_list_tab[-1] - self.p_list_tab[0])
        p_rec = self.points[:, 0] * scale
        T_rec = self.points[:, 1]
        self.pt_kdtree = KDTree(np.array([p_rec, T_rec]).T)

        # 构建要求解的各项参数
        self.physical_properties_array = self.cal_physical_properties_data(
            self.points[:, 0], self.points[:, 1] + 273.15)

        # 将所有数据存入缓存
        _tab_cache[self.tab_file] = {
            'points': self.points,
            'params_indices_in_tabparams': self.params_indices_in_tabparams,
            'standard_condition_data': self.standard_condition_data,
            'pt_kdtree': self.pt_kdtree,
            'physical_properties_array': self.physical_properties_array,
            'p_list_tab': self.p_list_tab,
            'T_list_tab': self.T_list_tab
        }
        log.info("构建物性缓存完成")



    def _read_tab(self):
        """读取表的数据, 会在初始化进行预读取"""
        processor = CsvDataProcessor(self.tab_file)
        COLUMNS_data, data_array, self.standard_condition_data = processor.load()

        # 检索tab文件变量缩写在tab表缩写参数大全中的位置
        self.params_indices_in_tabparams = find_indices(
            np.array(TabParams.name), np.array(COLUMNS_data[0]))
        self.points = data_array

    def _interp_array(self, var_array):
        """ 对数组进行插值

        """
        # 直接使用已缓存的kdtree
        scale = np.abs(self.T_list_tab[-1] - self.T_list_tab[0]) / np.abs(self.p_list_tab[-1] - self.p_list_tab[0])
        p_rec = self.search_points[:, 0] * scale
        T_rec = self.search_points[:, 1]
        
        _, idx = self.pt_kdtree.query(np.array([p_rec, T_rec]).T, 4)

        dist_rec = np.sqrt((var_array[:, :2][idx][:, :, 0] - np.array([self.search_points[:, 0]]).T)**2 + (var_array[:, :2][idx][:, :, 1] - np.array([self.search_points[:, 1]]).T)**2)

        conditions = [dist_rec[:,:,np.newaxis].min(axis=1) < 1e-12, dist_rec[:,:,np.newaxis].min(axis=1) > 1e7]
        
        choices = [var_array[idx][np.arange(idx.shape[0]), np.argmin(dist_rec, axis=1), :], np.nan]

        search_val = np.select(conditions, choices, default=np.einsum('ijk, ij->ik', var_array[idx], 1/(dist_rec + 1e-12)) / np.sum(1/(dist_rec + 1e-12), axis=1)[:, np.newaxis])
        return search_val.T

    def get_standard_data_in_tab(self):
        """
        获取标况数据
        :return: dict, 标况数据
        """
        standard_condition_data = {}
        standard_condition_data['STDPRESSURE'] = self.standard_condition_data[0]
        standard_condition_data['STDTEMPERATURE'] = self.standard_condition_data[1]
        standard_condition_data['GOR'] = self.standard_condition_data[2]
        standard_condition_data['GLR'] = self.standard_condition_data[3]
        standard_condition_data['WC'] = self.standard_condition_data[4]
        standard_condition_data['STDGASDENSITY'] = self.standard_condition_data[5]
        standard_condition_data['STDOILDENSITY'] = self.standard_condition_data[6]
        standard_condition_data['STDWATDENSITY'] = self.standard_condition_data[7]
        return standard_condition_data

    # test1
    def cal_physical_properties_data(self, pressure, temperature):
        """
        根据压力和温度计算物性数据
        :param pressure: 压力
        :param temperature: 温度
        :return: FormattedDict, 带有格式化输出功能的物性数据字典
        """

        # 转换成搜索格式
        self.search_points = np.array([pressure, temperature]).T

        # ! 温度单位换算由K氏温度换算为摄氏温度
        self.search_points[:, 1] = self.search_points[:, 1] - 273.15

        # 插值数据点
        decorated = add_notation_to_tab_data(params_indices_in_tabparams=self.params_indices_in_tabparams)(self._interp_array)

        # 获得物性数据
        tab_properties_data = decorated(self.points)

        # 物性数据打包
        physical_properties_data = {}

        # =================================================
        # 基本参数(从tab表直接获取)
        # =================================================
        physical_properties_data['pressure'] = self.search_points[:, 0]
        physical_properties_data['temperature'] = self.search_points[:, 1]
        physical_properties_data['gas_mass_fraction_in_gas/oil_mixture'] = tab_properties_data[
            'gas_mass_fraction_in_gas/oil_mixture']
        physical_properties_data['water_vapour_mass_fraction_in_gas_phase'] = tab_properties_data[
            'water_vapour_mass_fraction_in_gas_phase']
        physical_properties_data['oil_density'] = tab_properties_data['oil_density']
        physical_properties_data['gas_density'] = tab_properties_data['gas_density']
        physical_properties_data['water_density'] = tab_properties_data['water_density']
        physical_properties_data['derivative_of_water_density_w.r.t_temperature'] = tab_properties_data[
            'derivative_of_water_density_w.r.t_temperature']
        physical_properties_data['derivative_of_gas_density_w.r.t_temperature'] = tab_properties_data[
            'derivative_of_gas_density_w.r.t_temperature']
        physical_properties_data['derivative_of_oil_density_w.r.t_temperature'] = tab_properties_data[
            'derivative_of_oil_density_w.r.t_temperature']
        physical_properties_data['derivative_of_liquid_density_w.r.t_temperature'] = tab_properties_data[
            'derivative_of_water_density_w.r.t_temperature'] + tab_properties_data[
            'derivative_of_oil_density_w.r.t_temperature']

        physical_properties_data['derivative_of_water_density_w.r.t_pressure'] = tab_properties_data[
            'derivative_of_water_density_w.r.t_pressure']
        physical_properties_data['derivative_of_gas_density_w.r.t_pressure'] = tab_properties_data[
            'derivative_of_gas_density_w.r.t_pressure']
        physical_properties_data['derivative_of_oil_density_w.r.t_pressure'] = tab_properties_data[
            'derivative_of_oil_density_w.r.t_pressure']
        physical_properties_data['derivative_of_liquid_density_w.r.t_pressure'] = tab_properties_data[
            'derivative_of_water_density_w.r.t_pressure'] + tab_properties_data[
            'derivative_of_oil_density_w.r.t_pressure']
        physical_properties_data['gas_viscosity'] = tab_properties_data['gas_viscosity']
        physical_properties_data['oil_viscosity'] = tab_properties_data['oil_viscosity']
        physical_properties_data['water_viscosity'] = tab_properties_data['water_viscosity']
        physical_properties_data['gas_heat_capacity'] = tab_properties_data['gas_thermal_capacity']
        physical_properties_data['oil_heat_capacity'] = tab_properties_data['oil_thermal_capacity']
        physical_properties_data['water_heat_capacity'] = tab_properties_data['water_thermal_capacity']
        physical_properties_data['oil_heat_conductivity'] = tab_properties_data['oil_thermal_conductivity']
        physical_properties_data['gas_heat_conductivity'] = tab_properties_data['gas_thermal_conductivity']
        physical_properties_data['water_heat_conductivity'] = tab_properties_data['water_thermal_conductivity']
        physical_properties_data['oil_enthalpy'] = tab_properties_data['oil_enthalpy']
        physical_properties_data['gas_enthalpy'] = tab_properties_data['gas_enthalpy']
        physical_properties_data['water_enthalpy'] = tab_properties_data['water_enthalpy']
        physical_properties_data['gas_entropy'] = tab_properties_data['gas_entropy']
        physical_properties_data['oil_entropy'] = tab_properties_data['oil_entropy']
        physical_properties_data['water_entropy'] = tab_properties_data['water_entropy']
        physical_properties_data['surface_tension_between_gas_and_oil'] = tab_properties_data[
            'surface_tension_between_gas_and_oil']
        physical_properties_data['surface_tension_between_gas_and_water'] = tab_properties_data[
            'surface_tension_between_gas_and_water']
        physical_properties_data['surface_tension_between_oil_and_water'] = tab_properties_data[
            'surface_tension_between_oil_and_water']

        phase_type = self.get_standard_phase_type()  # 利用标况获取相态
        if phase_type == FluidPhaseType.Oil_Water:
            physical_properties_data['liquid_surface_tension'] = tab_properties_data[
                'surface_tension_between_oil_and_water']
        elif phase_type == FluidPhaseType.Water_Gas:
            physical_properties_data['liquid_surface_tension'] = tab_properties_data[
                'surface_tension_between_gas_and_water']
        elif phase_type == FluidPhaseType.Oil_Gas:
            physical_properties_data['liquid_surface_tension'] = tab_properties_data[
                'surface_tension_between_gas_and_oil']
        elif phase_type == FluidPhaseType.Tri_phase:
            physical_properties_data['liquid_surface_tension'] = cal_liquid_surface_tension(physical_properties_data,
                                                                                            self.get_standard_data_in_tab())
        else:  # 单相流
            physical_properties_data['liquid_surface_tension'] = np.zeros_like(self.search_points[:, 0])

        # =================================================
        # 从基本的物性参数计算其他物性参数
        # =================================================
        # 分数相关计算
        physical_properties_data['water_volume_fraction'] = cal_water_volume_fraction(physical_properties_data,
                                                                                      self.get_standard_data_in_tab())
        physical_properties_data['oil_volume_fraction'] = cal_oil_volume_fraction(physical_properties_data,
                                                                                  self.get_standard_data_in_tab())
        physical_properties_data['liquid_volume_fraction'] = cal_liquid_volume_fraction(physical_properties_data,
                                                                                        self.get_standard_data_in_tab())
        physical_properties_data['gas_volume_fraction'] = cal_gas_volume_fraction(physical_properties_data,
                                                                                  self.get_standard_data_in_tab())
        physical_properties_data['water_mass_fraction'] = cal_water_mass_fraction(physical_properties_data,
                                                                                  self.get_standard_data_in_tab())
        physical_properties_data['oil_mass_fraction'] = cal_oil_mass_fraction(physical_properties_data,
                                                                              self.get_standard_data_in_tab())
        physical_properties_data['gas_mass_fraction'] = cal_gas_mass_fraction(physical_properties_data,
                                                                              self.get_standard_data_in_tab())
        physical_properties_data['liquid_mass_fraction'] = cal_liquid_mass_fraction(physical_properties_data,
                                                                                    self.get_standard_data_in_tab())

        # 密度相关计算
        physical_properties_data['mixture_density'] = cal_mixture_density(physical_properties_data,
                                                                          self.get_standard_data_in_tab())
        physical_properties_data['liquid_density'] = cal_liquid_density(physical_properties_data,
                                                                        self.get_standard_data_in_tab())

        # 粘度相关计算
        physical_properties_data['liquid_viscosity'] = cal_liquid_viscosity(physical_properties_data,
                                                                            self.get_standard_data_in_tab())
        physical_properties_data['mixture_viscosity'] = cal_mixture_viscosity(physical_properties_data,
                                                                              self.get_standard_data_in_tab())

        # 比热容相关计算
        physical_properties_data['liquid_heat_capacity'] = cal_liquid_heat_capacity(physical_properties_data,
                                                                                    self.get_standard_data_in_tab())
        physical_properties_data['mixture_heat_capacity'] = cal_mixture_heat_capacity(physical_properties_data,
                                                                                      self.get_standard_data_in_tab())

        # 导热系数相关计算
        physical_properties_data['liquid_heat_conductivity'] = cal_liquid_heat_conductivity(physical_properties_data,
                                                                                            self.get_standard_data_in_tab())
        physical_properties_data['mixture_heat_conductivity'] = cal_mixture_heat_conductivity(physical_properties_data,
                                                                                              self.get_standard_data_in_tab())

        # 热膨胀系数相关计算
        physical_properties_data['liquid_thermal_expansion_coefficient'] = cal_liquid_thermal_expansion_coefficient(
            physical_properties_data, self.get_standard_data_in_tab())
        physical_properties_data['gas_thermal_expansion_coefficient'] = cal_gas_thermal_expansion_coefficient(
            physical_properties_data)
        physical_properties_data['mixture_thermal_expansion_coefficient'] = cal_mixture_thermal_expansion_coefficient(
            physical_properties_data, self.get_standard_data_in_tab())

        # 焓值相关计算
        physical_properties_data['liquid_enthalpy'] = cal_liquid_enthalpy(physical_properties_data,
                                                                          self.get_standard_data_in_tab())
        physical_properties_data['mixture_enthalpy'] = cal_mixture_enthalpy(physical_properties_data,
                                                                            self.get_standard_data_in_tab())

        # 其他参数计算
        physical_properties_data['mixture_entropy'] = cal_mixture_entropy(physical_properties_data,
                                                                          self.get_standard_data_in_tab())
        try:  # TODO: 气体分子量计算
            physical_properties_data['gas_molecular_weight'] = cal_gas_molecular_weight(physical_properties_data,
                                                                                        self.get_standard_data_in_tab())
        except:
            physical_properties_data['gas_molecular_weight'] = np.zeros_like(self.search_points[:, 0])

        physical_properties_data['gas_compressibility'] = cal_gas_compressibility(physical_properties_data,
                                                                                  self.get_standard_data_in_tab())

        for key, value in physical_properties_data.items():
            if not isinstance(value, np.ndarray):
                physical_properties_data[key] = np.zeros_like(self.search_points[:, 0])
        # 组合数据为数组
        physical_properties_array = np.array(list(physical_properties_data.values())).T

        return physical_properties_array


    def get_physical_properties_data(self, pressure, temperature):
        """
        根据压力和温度计算物性数据
        :param pressure: 压力
        :param temperature: 温度
        :return: FormattedDict, 带有格式化输出功能的物性数据字典
        """
        if not self.iscache:
            self.build_cache()

        if isinstance(pressure, np.ndarray):
            self.search_points = np.array([pressure, temperature]).T
        else:
            self.search_points = np.array([pressure, temperature]).reshape(1, -1)

        # 搜索时转换成摄氏度搜索
        self.search_points[:, 1] = self.search_points[:, 1] - 273.15

        # 插值数据点
        physical_properties_array = self._interp_array(self.physical_properties_array).T

        # 物性数据打包
        physical_properties_data = {}

        # =================================================
        # 基本参数(从tab表直接获取)
        # =================================================
        # todo:2025-0103-1607 恢复到zhaoliang版本 待修改测试
        physical_properties_data['pressure'] = physical_properties_array[:, 0]
        physical_properties_data['temperature'] = physical_properties_array[:, 1] + 273.15
        physical_properties_data['gas_mass_fraction_in_gas/oil_mixture'] = physical_properties_array[:, 2]
        physical_properties_data['water_vapour_mass_fraction_in_gas_phase'] = physical_properties_array[:, 3]
        physical_properties_data['oil_density'] = physical_properties_array[:, 4]
        physical_properties_data['gas_density'] = physical_properties_array[:, 5]
        physical_properties_data['water_density'] = physical_properties_array[:, 6]
        physical_properties_data['derivative_of_water_density_w.r.t_temperature'] = physical_properties_array[:, 7]
        physical_properties_data['derivative_of_gas_density_w.r.t_temperature'] = physical_properties_array[:, 8]
        physical_properties_data['derivative_of_oil_density_w.r.t_temperature'] = physical_properties_array[:, 9]
        physical_properties_data['derivative_of_liquid_density_w.r.t_temperature'] = physical_properties_array[:, 10]
        physical_properties_data['derivative_of_water_density_w.r.t_pressure'] = physical_properties_array[:, 11]
        physical_properties_data['derivative_of_gas_density_w.r.t_pressure'] = physical_properties_array[:, 12]
        physical_properties_data['derivative_of_oil_density_w.r.t_pressure'] = physical_properties_array[:, 13]
        physical_properties_data['derivative_of_liquid_density_w.r.t_pressure'] = physical_properties_array[:, 14]
        physical_properties_data['gas_viscosity'] = physical_properties_array[:, 15]

        physical_properties_data['oil_viscosity'] = physical_properties_array[:, 16]
        physical_properties_data['water_viscosity'] = physical_properties_array[:, 17]
        physical_properties_data['gas_heat_capacity'] = physical_properties_array[:, 18]
        physical_properties_data['oil_heat_capacity'] = physical_properties_array[:, 19]
        physical_properties_data['water_heat_capacity'] = physical_properties_array[:, 20]
        physical_properties_data['oil_heat_conductivity'] = physical_properties_array[:, 21]
        physical_properties_data['gas_heat_conductivity'] = physical_properties_array[:, 22]
        physical_properties_data['water_heat_conductivity'] = physical_properties_array[:, 23]

        physical_properties_data['oil_enthalpy'] = physical_properties_array[:, 24]
        physical_properties_data['gas_enthalpy'] = physical_properties_array[:, 25]
        physical_properties_data['water_enthalpy'] = physical_properties_array[:, 26]
        physical_properties_data['gas_entropy'] = physical_properties_array[:, 27]

        physical_properties_data['oil_entropy'] = physical_properties_array[:, 28]
        physical_properties_data['water_entropy'] = physical_properties_array[:, 29]
        physical_properties_data['surface_tension_between_gas_and_oil'] = physical_properties_array[:, 30]
        physical_properties_data['surface_tension_between_gas_and_water'] = physical_properties_array[:, 31]
        physical_properties_data['surface_tension_between_oil_and_water'] = physical_properties_array[:, 32]

        physical_properties_data['liquid_surface_tension'] = physical_properties_array[:, 33]


        # =================================================
        # 从基本的物性参数计算其他物性参数
        # =================================================
        # 分数相关计算
        physical_properties_data['water_volume_fraction'] = physical_properties_array[:, 34]
        physical_properties_data['oil_volume_fraction'] = physical_properties_array[:, 35]
        physical_properties_data['liquid_volume_fraction'] = physical_properties_array[:, 36]
        physical_properties_data['gas_volume_fraction'] = physical_properties_array[:, 37]

        physical_properties_data['water_mass_fraction'] = physical_properties_array[:, 38]
        physical_properties_data['oil_mass_fraction'] = physical_properties_array[:, 39]
        physical_properties_data['gas_mass_fraction'] = physical_properties_array[:, 40]
        physical_properties_data['liquid_mass_fraction'] = physical_properties_array[:, 41]


        # 密度相关计算
        physical_properties_data['mixture_density'] = physical_properties_array[:, 42]
        physical_properties_data['liquid_density'] = physical_properties_array[:, 43]


        # 粘度相关计算
        physical_properties_data['liquid_viscosity'] = physical_properties_array[:, 44]
        physical_properties_data['mixture_viscosity'] = physical_properties_array[:, 45]


        # 比热容相关计算
        physical_properties_data['liquid_heat_capacity'] = physical_properties_array[:, 46]
        physical_properties_data['mixture_heat_capacity'] = physical_properties_array[:, 47]


        # 导热系数相关计算
        physical_properties_data['liquid_heat_conductivity'] = physical_properties_array[:, 48]
        physical_properties_data['mixture_heat_conductivity'] = physical_properties_array[:, 49]


        # 热膨胀系数相关计算
        physical_properties_data['liquid_thermal_expansion_coefficient'] = physical_properties_array[:, 50]
        physical_properties_data['gas_thermal_expansion_coefficient'] = physical_properties_array[:, 51]
        physical_properties_data['mixture_thermal_expansion_coefficient'] = physical_properties_array[:, 52]


        # 焓值相关计算
        physical_properties_data['liquid_enthalpy'] = physical_properties_array[:, 53]
        physical_properties_data['mixture_enthalpy'] = physical_properties_array[:, 54]


        # 其他参数计算
        physical_properties_data['mixture_entropy'] =  physical_properties_array[:, 55]
        physical_properties_data['gas_molecular_weight'] = physical_properties_array[:, 56]
        physical_properties_data['gas_compressibility'] = physical_properties_array[:, 57]

        for key, value in physical_properties_data.items():
            if value.shape == (1,):
                physical_properties_data[key] = value[0]

        return physical_properties_data


    # test2
    def get_standard_condition_data(self):
        """
        获取标况状态下的物性参数
        :return: FormattedDict, 带有格式化输出功能的字典
        """
        p = 101325
        T = 273.15
        return self.get_physical_properties_data(p, T)

    # test3
    # def calculate_temperature(self, pressure, enthalpy):
    #     """
    #     通过压力和混合焓值获取温度

    #     Args:
    #         pressure (float): 压力
    #         enthalpy (float): 混合焓值

    #     Returns:
    #         float: 温度
    #     """
    #     # 搜索目标点(pressure, enthalpy)附近的4个点
    #     search_point = np.array([pressure, enthalpy])
    #     dist, idx = self.ph_T_kdtree.query(search_point, 2)

    #     # 插值计算温度
    #     if dist.min() < 1e-6:  # 如果找到完全匹配的点
    #         idx_min = np.where(dist == dist.min())
    #         T = self.ph_T_points[idx[idx_min]][0][2]
    #     elif dist.min() > 1e7:  # 如果点太远
    #         raise ValueError("搜索点离数据区域太远，不建议插值")
    #     else:
    #         # 使用反距离权重插值
    #         w = 1 / dist
    #         T = np.dot(w, self.ph_T_points[idx][:, 2]) / np.sum(w)

    #     return T + 273.15  # 转换回K

    # test4
    def calculate_enthalpy(self, pressure, temperature):
        """
        通过压力温度获取混合焓值
        :param pressure: 压力
        :param temperature: 温度
        :return: 焓值
        """
        physical_properties_data = self.get_physical_properties_data(
            pressure, temperature)
        mixture_enthalpy = physical_properties_data['mixture_enthalpy']
        return mixture_enthalpy

    # test5
    def is_single_phase_flow(self, pressure, temperature):
        """
        根据标准密度判断是否为单相流

        Returns:
            bool: 是否为单相流
        """
        physical_properties_data = self.get_physical_properties_data(
            pressure, temperature)
        gas_density = physical_properties_data['gas_density']
        oil_density = physical_properties_data['oil_density']
        water_density = physical_properties_data['water_density']
        if gas_density > -999 and oil_density == -999 and water_density == -999:
            return True
        elif gas_density == -999 and oil_density > -999 and water_density == -999:
            return True
        elif gas_density == -999 and oil_density == -999 and water_density > -999:
            return True
        else:
            return False

    # test6
    def get_standard_phase_type(self):
        # 获取标准密度数据
        std_density = self.get_standard_data_in_tab()

        # 1. 气相判断
        if (std_density['STDGASDENSITY'] > -999 and
                std_density['STDOILDENSITY'] == -999 and
                std_density['STDWATDENSITY'] == -999):
            return FluidPhaseType.Gas

        # 2. 油相判断
        if (std_density['STDOILDENSITY'] > -999 and
                std_density['STDGASDENSITY'] == -999 and
                std_density['STDWATDENSITY'] == -999):
            return FluidPhaseType.Oil

        # 3. 水相判断
        if (std_density['STDWATDENSITY'] > -999 and
                std_density['STDGASDENSITY'] == -999 and
                std_density['STDOILDENSITY'] == -999):
            return FluidPhaseType.Water

        # 4. 油水两相判断
        if (std_density['STDOILDENSITY'] > -999 and
                std_density['STDWATDENSITY'] > -999 and
                std_density['STDGASDENSITY'] == -999):
            return FluidPhaseType.Oil_Water

        # 5. 气水两相判断
        if (std_density['STDGASDENSITY'] > -999 and
                std_density['STDWATDENSITY'] > -999 and
                std_density['STDOILDENSITY'] == -999):
            return FluidPhaseType.Water_Gas

        # 6. 气油两相判断
        if (std_density['STDGASDENSITY'] > -999 and
                std_density['STDOILDENSITY'] > -999 and
                std_density['STDWATDENSITY'] == -999):
            return FluidPhaseType.Oil_Gas

        # 7. 三相判断
        if (std_density['STDGASDENSITY'] > -999 and
                std_density['STDOILDENSITY'] > -999 and
                std_density['STDWATDENSITY'] > -999):
            return FluidPhaseType.Tri_phase

        raise ValueError("流体相态判断失败, 请检查标准密度数据")

    def get_phase_type(self, pressure, temperature):
        """
        根据标准密度判断流体相态

        Returns:
            FluidPhaseType: 流体相态类型
        """
        physical_properties_data = self.get_physical_properties_data(
            pressure, temperature)
        gas_density = physical_properties_data['gas_density']
        oil_density = physical_properties_data['oil_density']
        water_density = physical_properties_data['water_density']
        if gas_density > 0 and oil_density == 0 and water_density == 0:
            return FluidPhaseType.Gas
        elif gas_density == 0 and oil_density > 0 and water_density == 0:
            return FluidPhaseType.Oil
        elif gas_density == 0 and oil_density == 0 and water_density > 0:
            return FluidPhaseType.Water
        elif gas_density == 0 and oil_density > 0 and water_density > 0:
            return FluidPhaseType.Oil_Water
        elif gas_density > 0 and oil_density == 0 and water_density > 0:
            return FluidPhaseType.Water_Gas
        elif gas_density > 0 and oil_density > 0 and water_density == 0:
            return FluidPhaseType.Oil_Gas
        elif gas_density > 0 and oil_density > 0 and water_density > 0:
            return FluidPhaseType.Tri_phase
        else:
            # log.error(
            #     f"pressure: {pressure}, temperature: {temperature}, gas_density: {gas_density}, oil_density: {oil_density}, water_density: {water_density}")
            print(
                f"pressure: {pressure}, temperature: {temperature}, gas_density: {gas_density}, oil_density: {oil_density}, water_density: {water_density}")
            raise ValueError("流体相态判断失败, 请检查标准密度数据")

    def __str__(self):
        """
        格式化输出物性计算器的信息
        """
        info = "流体物性计算器:\n"
        info += f"  流体类型: {self.fluid_type}\n"
        info += f"  TAB文件: {self.tab_file}\n"
        return info

    def _format_dict(self, data_dict, indent=2):
        """
        格式化字典输出

        Args:
            data_dict (dict): 需要格式化的字典
            indent (int): 缩进空格数

        Returns:
            str: 格式化后的字符串
        """
        if not data_dict:
            return "  空字典"

        # 找出最长的键名，用于对齐
        max_key_length = max(len(str(key)) for key in data_dict.keys())

        # 格式化每一行
        formatted_lines = []
        for key, value in data_dict.items():
            # 对齐键名，并根据值的类型格式化值
            if isinstance(value, float):
                formatted_lines.append(
                    f"{' ' * indent}{str(key):<{max_key_length}} : {value:.6e}")
            else:
                formatted_lines.append(
                    f"{' ' * indent}{str(key):<{max_key_length}} : {value}")

        return "\n".join(formatted_lines)


# ================================================================
# 需要额外计算的物性参数
# ================================================================

# 1
def cal_standard_mass_all(standard_condition_data):
    """计算标准条件下混合物的质量
    """
    wc = standard_condition_data['WC']
    GOR = standard_condition_data['GOR']
    GLR = standard_condition_data['GLR']
    standard_water_density = standard_condition_data['STDWATDENSITY']
    standard_oil_density = standard_condition_data['STDOILDENSITY']
    standard_gas_density = standard_condition_data['STDGASDENSITY']

    if standard_water_density == -999:
        standard_water_density = 0
    if standard_oil_density == -999:
        standard_oil_density = 0
    if standard_gas_density == -999:
        standard_gas_density = 0
    if wc == -999:
        wc = 0
    if GOR == -999:
        GOR = 0
    if GLR == -999:
        GLR = 0

    if wc == 1:
        M_all_standard = standard_water_density + standard_gas_density * GLR
    else:
        M_all_standard = standard_water_density * wc / \
            (1 - wc) + standard_oil_density + standard_gas_density * GOR
    return M_all_standard

# 2
def cal_standard_water_mass_fraction(standard_condition_data):
    """计算标准条件下水相质量分数
    """
    wc = standard_condition_data['WC']
    standard_water_density = standard_condition_data['STDWATDENSITY']

    if standard_water_density == -999:
        standard_water_density = 0
    if wc == -999:
        wc = 0
    if wc == 1:
        water_mass_fraction = standard_water_density / \
            cal_standard_mass_all(standard_condition_data)
    else:
        water_mass_fraction = standard_water_density * wc / \
            (1 - wc) / cal_standard_mass_all(standard_condition_data)
    return water_mass_fraction

# 3
def cal_standard_gas_mass_fraction(standard_condition_data):
    """计算标准条件下气相质量分数
    """
    GOR = standard_condition_data['GOR']
    standard_gas_density = standard_condition_data['STDGASDENSITY']
    if standard_gas_density == -999:
        standard_gas_density = 0
    if GOR == -999:
        GOR = 0
    gas_mass_fraction = standard_gas_density * GOR / \
        cal_standard_mass_all(standard_condition_data)
    return gas_mass_fraction

# 4
def cal_standard_oil_mass_fraction(standard_condition_data):
    """计算标准条件下油相质量分数
    """
    standard_oil_density = standard_condition_data['STDOILDENSITY']
    if standard_oil_density == -999:
        standard_oil_density = 0
    oil_mass_fraction = standard_oil_density / \
        cal_standard_mass_all(standard_condition_data)
    return oil_mass_fraction

# 5
def cal_standard_water_mass(standard_condition_data):
    """计算标准条件下水的质量
    """
    wc = standard_condition_data['WC']
    standard_water_density = standard_condition_data['STDWATDENSITY']
    if standard_water_density == -999:
        standard_water_density = 0
    if wc == -999:
        wc = 0
    if wc == 1:
        standard_water_mass = standard_water_density
    else:
        standard_water_mass = standard_water_density * wc / (1 - wc)
    return standard_water_mass

# 6
# TODO: 需要验证
def cal_oil_mass(physical_properties_data, standard_condition_data):
    """计算工况下油的质量
    """
    Rs = physical_properties_data['gas_mass_fraction_in_gas/oil_mixture']
    standard_mass_all = cal_standard_mass_all(standard_condition_data)
    standard_water_mass = cal_standard_water_mass(standard_condition_data)
    oil_mass = (standard_mass_all - standard_water_mass) * (1 - Rs)
    return oil_mass

# 7
# TODO: 需要验证
def cal_gas_mass_without_water(physical_properties_data, standard_condition_data):
    """ 计算工况下气的质量, 不包含水
    """
    Rs = physical_properties_data['gas_mass_fraction_in_gas/oil_mixture']
    if isinstance(Rs, np.ndarray):
        oil_mass = cal_oil_mass(physical_properties_data,
                                standard_condition_data)
        standard_mass_all = cal_standard_mass_all(standard_condition_data)
        standard_water_mass = cal_standard_water_mass(standard_condition_data)
        gas_mass_without_water = np.where(Rs < 1, oil_mass * Rs / (1 - Rs), (standard_mass_all - standard_water_mass) * Rs)
    else:
        if 0 <= Rs < 1:
            oil_mass = cal_oil_mass(physical_properties_data,
                                standard_condition_data)
            gas_mass_without_water = oil_mass * Rs / (1 - Rs)
        else:
            standard_mass_all = cal_standard_mass_all(standard_condition_data)
            standard_water_mass = cal_standard_water_mass(standard_condition_data)
            gas_mass_without_water = (standard_mass_all - standard_water_mass) * Rs
    return gas_mass_without_water

# 8
def cal_vapor_mass(physical_properties_data, standard_condition_data):
    """计算工况下气相中水蒸气的质量
    """
    RSW = physical_properties_data['water_vapour_mass_fraction_in_gas_phase']
    standard_gas_mass_without_water = cal_gas_mass_without_water(
        physical_properties_data, standard_condition_data)
    vapor_mass = RSW / (1 - RSW) * standard_gas_mass_without_water
    return vapor_mass

# 9
# TODO: 需要验证
def cal_water_mass(physical_properties_data, standard_condition_data):
    """ 计算工况下水的质量
    """
    # standard_water_mass = cal_standard_water_mass(standard_condition_data)
    # vapor_mass = cal_vapor_mass(physical_properties_data, standard_condition_data)
    # water_mass = standard_water_mass - vapor_mass
    return cal_standard_water_mass(standard_condition_data)








# 21
def cal_water_mass_fraction(physical_properties_data, standard_condition_data):
    """计算工况下水相的质量分数
    """
    water_mass = cal_water_mass(
        physical_properties_data, standard_condition_data)
    standard_mass_all = cal_standard_mass_all(standard_condition_data)
    water_mass_fraction = water_mass / standard_mass_all
    return water_mass_fraction

# 22
def cal_oil_mass_fraction(physical_properties_data, standard_condition_data):
    """计算工况下油相的质量分数
    """
    oil_mass = cal_oil_mass(physical_properties_data, standard_condition_data)
    standard_mass_all = cal_standard_mass_all(standard_condition_data)
    oil_mass_fraction = oil_mass / standard_mass_all
    return oil_mass_fraction

# 23
# TODO: 需要验证
def cal_gas_mass_fraction(physical_properties_data, standard_condition_data):
    """计算工况下气相的质量分数
    """
    # gas_mass = cal_gas_mass_without_water(physical_properties_data, standard_condition_data)
    # vapor_mass = cal_vapor_mass(physical_properties_data, standard_condition_data)
    # standard_mass_all = cal_standard_mass_all(standard_condition_data)
    # gas_mass_fraction = (gas_mass + vapor_mass) / standard_mass_all
    gas_mass = cal_gas_mass_without_water(
        physical_properties_data, standard_condition_data)
    standard_mass_all = cal_standard_mass_all(standard_condition_data)
    gas_mass_fraction = gas_mass / standard_mass_all
    return gas_mass_fraction

# 24
def cal_water_volume_fraction(physical_properties_data, standard_condition_data):
    """计算水相体积分数

    """
    if isinstance(physical_properties_data['water_density'], np.ndarray):
        water_volume_fraction = np.where(physical_properties_data['water_density'] != 0, cal_water_mass(physical_properties_data, standard_condition_data) / \
            physical_properties_data['water_density'] / cal_volume_all(physical_properties_data,
                                                                       standard_condition_data), 0)
    else:
        if physical_properties_data['water_density'] == 0:
            return 0
        else:
            water_volume_fraction = cal_water_mass(physical_properties_data, standard_condition_data) / \
            physical_properties_data['water_density'] / cal_volume_all(physical_properties_data,
                                                                       standard_condition_data)
    return water_volume_fraction

# 25
def cal_liquid_enthalpy(physical_properties_data, standard_condition_data):
    """ 计算液相焓值
    """
    liquid_enthalpy = (physical_properties_data['water_enthalpy'] * cal_water_mass_fraction(physical_properties_data,
                                                                                            standard_condition_data) +
                       physical_properties_data['oil_enthalpy'] * cal_oil_mass_fraction(physical_properties_data,
                                                                                        standard_condition_data)) / (
                                  cal_water_mass_fraction(physical_properties_data,
                                                          standard_condition_data) + cal_oil_mass_fraction(
                              physical_properties_data, standard_condition_data))
    return liquid_enthalpy

# 26
def cal_mixture_enthalpy(physical_properties_data, standard_condition_data):
    """ 计算混合焓值
    """
    mixture_enthalpy = cal_gas_mass_fraction(physical_properties_data, standard_condition_data) * \
                       physical_properties_data['gas_enthalpy'] + cal_oil_mass_fraction(physical_properties_data,
                                                                                        standard_condition_data) * \
                       physical_properties_data['oil_enthalpy'] + cal_water_mass_fraction(physical_properties_data,
                                                                                          standard_condition_data) * \
                       physical_properties_data['water_enthalpy']

    return mixture_enthalpy

# 27
def cal_liquid_surface_tension(physical_properties_data, standard_condition_data):
    """ 计算液相界面张力
    """
    water_volume_fraction = cal_water_volume_fraction(
        physical_properties_data, standard_condition_data)
    if isinstance(water_volume_fraction, np.ndarray):
        liquid_surface_tension = np.where(water_volume_fraction >= 0.6,
                                          physical_properties_data['surface_tension_between_gas_and_water'],
                                          physical_properties_data['surface_tension_between_gas_and_oil'])
    else:
        if water_volume_fraction >= 0.6:
            liquid_surface_tension = physical_properties_data['surface_tension_between_gas_and_water']
        else:
            liquid_surface_tension = physical_properties_data['surface_tension_between_gas_and_oil']
    return liquid_surface_tension

# 28
def cal_mixture_entropy(physical_properties_data, standard_condition_data):
    """计算混合比熵
    """
    mixture_entropy = cal_gas_mass_fraction(physical_properties_data, standard_condition_data) * \
        physical_properties_data['gas_entropy'] + cal_oil_mass_fraction(physical_properties_data,
                                                                        standard_condition_data) * \
        physical_properties_data['oil_entropy'] + cal_water_mass_fraction(physical_properties_data,
                                                                          standard_condition_data) * \
        physical_properties_data['water_entropy']
    return mixture_entropy

# 29
def cal_gas_compressibility(physical_properties_data, standard_condition_data):
    """计算气体压缩因子(CNGA),适用于相对密度在0.55~0.7之间, 压力介于0~6.89MPa之间, 温度介于272.2~333.3K之间
    """
    gas_compressibility = 1 / (1 + 5.072 * physical_properties_data['pressure'] * 10 ** (
        1.7785 * standard_condition_data['STDGASDENSITY'] / 1.293) / (
        physical_properties_data['temperature']) ** 3.825)
    return gas_compressibility

# 30
def find_indices(a: np.ndarray, b: np.ndarray) -> list:
    """ 找到数组a中b的索引

    Args:
        a (np.ndarray): _description_
        b (np.ndarray): _description_

    Returns:
        list: 索引列表
    """
    indices = []
    for element in b:
        index = np.where(a == element)[0]
        if index.size > 0:
            indices.append(index[0])
        else:
            pass
    return indices







def cal_liquid_mass_fraction(physical_properties_data, standard_condition_data):
    """计算工况下液相的质量分数
    """
    liquid_mass_fraction = cal_water_mass_fraction(physical_properties_data,
                                                   standard_condition_data) + cal_oil_mass_fraction(
        physical_properties_data, standard_condition_data)
    return liquid_mass_fraction


def cal_volume_all(physical_properties_data, standard_condition_data):
    """ 计算工况的总体积
    """
    if isinstance(physical_properties_data['water_density'], np.ndarray):
        volume_all = np.where(physical_properties_data['water_density'] != 0, cal_water_mass(physical_properties_data, standard_condition_data) / (physical_properties_data[
                'water_density'] + 1e-12) + cal_oil_mass(physical_properties_data, standard_condition_data) / \
                physical_properties_data['oil_density'] + cal_gas_mass_without_water(physical_properties_data,
                                                                                    standard_condition_data) / \
                physical_properties_data['gas_density'], cal_oil_mass(physical_properties_data, standard_condition_data) / physical_properties_data[
                'oil_density'] + cal_gas_mass_without_water(physical_properties_data, standard_condition_data) / \
                physical_properties_data['gas_density'])
    else:
        if physical_properties_data['water_density'] != 0:
            volume_all = cal_water_mass(physical_properties_data, standard_condition_data) / physical_properties_data[
                'water_density'] + cal_oil_mass(physical_properties_data, standard_condition_data) / \
                physical_properties_data['oil_density'] + cal_gas_mass_without_water(physical_properties_data,
                                                                                    standard_condition_data) / \
                physical_properties_data['gas_density']
        else:
            volume_all = cal_oil_mass(physical_properties_data, standard_condition_data) / physical_properties_data[
                'oil_density'] + cal_gas_mass_without_water(physical_properties_data, standard_condition_data) / \
                physical_properties_data['gas_density']
    return volume_all


def cal_water_volume_fraction(physical_properties_data, standard_condition_data):
    """计算水相体积分数

    """
    if isinstance(physical_properties_data['water_density'], np.ndarray):
        water_volume_fraction = np.where(physical_properties_data['water_density'] != 0, cal_water_mass(physical_properties_data, standard_condition_data) / \
            (physical_properties_data['water_density'] + 1e-12) / cal_volume_all(physical_properties_data, standard_condition_data), 0)
    else:
        if physical_properties_data['water_density'] == 0:
            return 0
        else:
            water_volume_fraction = cal_water_mass(physical_properties_data, standard_condition_data) / \
            physical_properties_data['water_density'] / cal_volume_all(physical_properties_data,
                                                                       standard_condition_data)
    return water_volume_fraction


def cal_oil_volume_fraction(physical_properties_data, standard_condition_data):
    """计算油相体积分数
    """
    oil_volume_fraction = cal_oil_mass(physical_properties_data, standard_condition_data) / physical_properties_data[
        'oil_density'] / cal_volume_all(physical_properties_data, standard_condition_data)
    return oil_volume_fraction


def cal_liquid_volume_fraction(physical_properties_data, standard_condition_data):
    """计算液相体积分数
    """
    liquid_volume_fraction = cal_water_volume_fraction(physical_properties_data,
                                                       standard_condition_data) + cal_oil_volume_fraction(
        physical_properties_data, standard_condition_data)
    return liquid_volume_fraction


def cal_gas_volume_fraction(physical_properties_data, standard_condition_data):
    """计算气相体积分数
    """
    gas_volume_fraction = 1 - \
        cal_liquid_volume_fraction(
            physical_properties_data, standard_condition_data)
    return gas_volume_fraction


def cal_mixture_density(physical_properties_data, standard_condition_data):
    """计算混合密度
    """
    mixture_density = physical_properties_data['water_density'] * cal_water_volume_fraction(physical_properties_data,
                                                                                            standard_condition_data) + \
        physical_properties_data['oil_density'] * cal_oil_volume_fraction(physical_properties_data,
                                                                          standard_condition_data) + \
        physical_properties_data['gas_density'] * cal_gas_volume_fraction(physical_properties_data,
                                                                          standard_condition_data)
    return mixture_density


def cal_liquid_density(physical_properties_data, standard_condition_data):
    """ 计算液相密度
    """
    liquid_density = (physical_properties_data['water_density'] * cal_water_volume_fraction(physical_properties_data, standard_condition_data) + physical_properties_data['oil_density'] * cal_oil_volume_fraction(physical_properties_data,standard_condition_data)) / (cal_water_volume_fraction(physical_properties_data,standard_condition_data) + cal_oil_volume_fraction(physical_properties_data, standard_condition_data))
    return liquid_density


def cal_liquid_viscosity(physical_properties_data, standard_condition_data):
    """ 计算液相粘度
    """
    liquid_viscosity = (physical_properties_data['water_viscosity'] * cal_water_volume_fraction(
        physical_properties_data, standard_condition_data) + physical_properties_data[
        'oil_viscosity'] * cal_oil_volume_fraction(physical_properties_data,
                                                   standard_condition_data)) / (
        cal_water_volume_fraction(physical_properties_data,
                                  standard_condition_data) + cal_oil_volume_fraction(
            physical_properties_data, standard_condition_data))
    return liquid_viscosity


def cal_mixture_viscosity(physical_properties_data, standard_condition_data):
    """ 计算混合粘度
    """
    mixture_viscosity = cal_gas_volume_fraction(physical_properties_data, standard_condition_data) * \
        physical_properties_data['gas_viscosity'] + cal_oil_volume_fraction(physical_properties_data,
                                                                            standard_condition_data) * \
        physical_properties_data['oil_viscosity'] + cal_water_volume_fraction(physical_properties_data,
                                                                              standard_condition_data) * \
        physical_properties_data['water_viscosity']
    return mixture_viscosity


def cal_liquid_heat_capacity(physical_properties_data, standard_condition_data):
    """计算液相比热容
    """
    liquid_heat_capacity = (physical_properties_data['water_heat_capacity'] * cal_water_mass_fraction(
        physical_properties_data, standard_condition_data) + physical_properties_data[
        'oil_heat_capacity'] * cal_oil_mass_fraction(physical_properties_data,
                                                     standard_condition_data)) / (
        cal_water_mass_fraction(physical_properties_data,
                                standard_condition_data) + cal_oil_mass_fraction(
            physical_properties_data, standard_condition_data))
    return liquid_heat_capacity


def cal_mixture_heat_capacity(physical_properties_data, standard_condition_data):
    """ 计算混合比热容
    """
    mixture_heat_capacity = cal_gas_mass_fraction(physical_properties_data, standard_condition_data) * \
        physical_properties_data['gas_heat_capacity'] + cal_oil_mass_fraction(
        physical_properties_data, standard_condition_data) * physical_properties_data[
        'oil_heat_capacity'] + cal_water_mass_fraction(physical_properties_data,
                                                       standard_condition_data) * \
        physical_properties_data['water_heat_capacity']
    return mixture_heat_capacity


def cal_liquid_heat_conductivity(physical_properties_data, standard_condition_data):
    """计算液相导热系数
    """
    liquid_heat_conductivity = (physical_properties_data['water_heat_conductivity'] * cal_water_mass_fraction(
        physical_properties_data, standard_condition_data) + physical_properties_data[
        'oil_heat_conductivity'] * cal_oil_mass_fraction(physical_properties_data,
                                                         standard_condition_data)) / (
        cal_water_mass_fraction(physical_properties_data,
                                standard_condition_data) + cal_oil_mass_fraction(
            physical_properties_data, standard_condition_data))
    return liquid_heat_conductivity


def cal_mixture_heat_conductivity(physical_properties_data, standard_condition_data):
    """计算混合导热系数
    """
    mixture_heat_conductivity = cal_gas_mass_fraction(physical_properties_data, standard_condition_data) * \
        physical_properties_data['gas_heat_conductivity'] + cal_oil_mass_fraction(
        physical_properties_data, standard_condition_data) * physical_properties_data[
        'oil_heat_conductivity'] + cal_water_mass_fraction(physical_properties_data,
                                                           standard_condition_data) * \
        physical_properties_data['water_heat_conductivity']
    return mixture_heat_conductivity


def cal_liquid_thermal_expansion_coefficient(physical_properties_data, standard_condition_data):
    """计算液相热膨胀系数
    """
    derivative_of_water_density_temperature = physical_properties_data[
        'derivative_of_water_density_w.r.t_temperature']
    derivative_of_oil_density_temperature = physical_properties_data[
        'derivative_of_oil_density_w.r.t_temperature']
    water_volume_fraction = cal_water_volume_fraction(
        physical_properties_data, standard_condition_data)
    oil_volume_fraction = cal_oil_volume_fraction(
        physical_properties_data, standard_condition_data)
    liquid_density = cal_liquid_density(
        physical_properties_data, standard_condition_data)
    liquid_thermal_expansion_coefficient = - 1 / liquid_density * (
        derivative_of_water_density_temperature * water_volume_fraction + derivative_of_oil_density_temperature * oil_volume_fraction) / (
        water_volume_fraction + oil_volume_fraction)
    return liquid_thermal_expansion_coefficient


def cal_gas_thermal_expansion_coefficient(physical_properties_data):
    """计算气相热膨胀系数
    """
    derivative_of_gas_density_temperature = physical_properties_data[
        'derivative_of_gas_density_w.r.t_temperature']
    gas_thermal_expansion_coefficient = - 1 / physical_properties_data[
        'gas_density'] * derivative_of_gas_density_temperature
    return gas_thermal_expansion_coefficient


def cal_mixture_thermal_expansion_coefficient(physical_properties_data, standard_condition_data):
    """计算混合热膨胀系数
    """
    mixture_density = cal_mixture_density(
        physical_properties_data, standard_condition_data)
    gas_volume_fraction = cal_gas_volume_fraction(
        physical_properties_data, standard_condition_data)
    water_volume_fraction = cal_water_volume_fraction(
        physical_properties_data, standard_condition_data)
    oil_volume_fraction = cal_oil_volume_fraction(
        physical_properties_data, standard_condition_data)
    derivative_of_water_density_temperature = physical_properties_data[
        'derivative_of_water_density_w.r.t_temperature']
    derivative_of_oil_density_temperature = physical_properties_data[
        'derivative_of_oil_density_w.r.t_temperature']
    derivative_of_gas_density_temperature = physical_properties_data[
        'derivative_of_gas_density_w.r.t_temperature']
    mixture_thermal_expansion_coefficient = -1 / mixture_density * (
        gas_volume_fraction * derivative_of_gas_density_temperature + water_volume_fraction * derivative_of_water_density_temperature + oil_volume_fraction * derivative_of_oil_density_temperature)
    return mixture_thermal_expansion_coefficient


def cal_gas_molecular_weight(physical_properties_data):
    """计算气体摩尔质量
    """
    pass


def cal_gas_compressibility(physical_properties_data, standard_condition_data):
    """计算气体压缩因子(CNGA),适用于相对密度在0.55~0.7之间, 压力介于0~6.89MPa之间, 温度介于272.2~333.3K之间
    """
    gas_compressibility = 1 / (1 + 5.072 * physical_properties_data['pressure'] * 10 ** (
        1.7785 * standard_condition_data['STDGASDENSITY'] / 1.293) / (
        physical_properties_data['temperature'] + 273.15) ** 3.825)
    return gas_compressibility


def find_indices(a: np.ndarray, b: np.ndarray) -> list:
    """ 找到数组a中b的索引

    Args:
        a (np.ndarray): _description_
        b (np.ndarray): _description_

    Returns:
        list: 索引列表
    """
    indices = []
    for element in b:
        index = np.where(a == element)[0]
        if index.size > 0:
            indices.append(index[0])
        else:
            pass
    return indices



# 读取tab文件
class CsvDataProcessor:
    def __init__(self, tab_path):
        self.tab_path = tab_path

    def csvloader(self):
        COLUMNS_data = []
        PVTTABLEpoint_data = []
        # 打开文件并读取内容
        self.standard_water_density = None
        self.WC = None
        tab_path = os.path.join(get_base_path(), self.tab_path)
        with open(tab_path, mode='r', encoding='latin-1') as file:
            csv_reader = csv.reader(file)
            for row in csv_reader:
                # 检查行中是否包含 "COLUMNS ="
                if any("COLUMNS =" in cell for cell in row):
                    COLUMNS_data.append(row)  # 仅保留符合条件的行
                if any("PVTTABLE POINT =" in cell for cell in row):
                    PVTTABLEpoint_data.append(row)  # 仅保留符合条件的行
                if any("STDGASDENSITY =" in cell for cell in row):
                    self.standard_gas_density = row[0]
                if any("STDOILDENSITY =" in cell for cell in row):
                    self.standard_oil_density = row[0]
                if any("STDWATDENSITY =" in cell for cell in row):
                    self.standard_water_density = row[0]
                if any("GOR =" in cell for cell in row):
                    self.GOR = row[0]
                if any("GLR =" in cell for cell in row):
                    self.GLR = row[0]
                if any("WC =" in cell for cell in row):
                    self.WC = row[0]
                # 避免文件格式不规范
                if any("WC=" in cell for cell in row):
                    self.WC = row[0]
                if any("STDPRESSURE =" in cell for cell in row):
                    self.STDPRESSURE = row[0]
                if any("STDTEMPERATURE =" in cell for cell in row):
                    self.STDTEMPERATURE = row[0]
        if self.standard_water_density is None:
            self.standard_water_density = -999
        if self.WC is None:
            self.WC = 0
        return COLUMNS_data, PVTTABLEpoint_data

    # 定义递归函数删除包含特定模式的元素
    def clean_data(self, data, patterns):
        cleaned_data = []

        for item in data:
            if isinstance(item, list):
                # 如果 item 是列表，递归调 clean_data
                cleaned_data.append(self.clean_data(item, patterns))
            else:
                # 对字符串应用所有的模式替换
                cleaned_item = str(item)
                for pattern in patterns:
                    cleaned_item = re.sub(pattern, '', cleaned_item)
                cleaned_data.append(cleaned_item)
        return cleaned_data

    def load(self):
        COLUMNS_data, PVTTABLEpoint_data = self.csvloader()
        # col = len(PVTTABLEpoint_data)
        # hel = len(COLUMNS_data[0])
        patterns = ["PVTTABLE POINT =", r'\(', r'\)', r'\s+']
        cleaned_data = self.clean_data(PVTTABLEpoint_data, patterns)
        data_array = np.array(cleaned_data, dtype=np.float64)

        patterns = ["COLUMNS =", r'\(', r'\)', r'\s+']
        COLUMNS_data = self.clean_data(COLUMNS_data, patterns)

        patterns = ["STDPRESSURE =", "ATM", "Pa", "STDTEMPERATURE =", "K", "GOR =", "GLR =", "WC =", "WC=", "STDGASDENSITY =",
                    "STDOILDENSITY =", "STDWATDENSITY =", "KG/M3", "kg/m3", "SM3/SM3", "Sm3/Sm3", "C", "PA", r'\(',
                    r'\)', r'\s+', 'G/M3']

        standard_data = self.clean_data(
            [self.STDPRESSURE, self.STDTEMPERATURE, self.GOR, self.GLR, self.WC, self.standard_gas_density,
             self.standard_oil_density, self.standard_water_density], patterns)

        standard_data = np.array(standard_data, dtype=np.float64)
        if 'ATM' in self.STDPRESSURE:
            standard_data[0] = standard_data[0]*101325
        return COLUMNS_data, data_array, standard_data


def add_notation_to_tab_data(params_indices_in_tabparams=None):
    """将tab表中的数据打包成字典

    Args:
        params_indices_in_tabparams: list; tab文件中变量在TabParams中的索引位置
    """
    dict_text = [
        "pressure",  # PT 压力 Pa
        "temperature",  # TM 温度 ℃
        "gas_density",  # ROG 气相密度 kg/m3
        "oil_density",  # ROHL 油相密度 kg/m3
        "water_density",  # ROWT 水相密度 kg/m3
        "derivative_of_gas_density_w.r.t_pressure",  # DROGDP 气相密度随压力的偏导 s2/m2
        "derivative_of_oil_density_w.r.t_pressure",  # DROHLDP 油相密度随压力的偏导 s2/m3
        "derivative_of_water_density_w.r.t_pressure",  # DROWTDP 水相密度随压力的偏导 s2/m4
        "derivative_of_gas_density_w.r.t_temperature",  # DROGDT 气相密度随温度的偏导 kg/m3.k
        "derivative_of_oil_density_w.r.t_temperature",  # DROHLDT 油相密度随温度的偏导 kg/m3.k
        "derivative_of_water_density_w.r.t_temperature",  # DROWTDT 水相密度随温度的偏导 kg/m3.k
        "gas_mass_fraction_in_gas/oil_mixture",  # RS 烃类(油+气混合物)中气相质量分数 /
        "water_vapour_mass_fraction_in_gas_phase",  # RSW 气相中水蒸气的质量分数 /
        "gas_viscosity",  # VISG 气相粘度 Pa.s
        "oil_viscosity",  # VISHL 油相粘度 Pa.s
        "water_viscosity",  # VISWT 水相粘度 Pa.s
        "gas_thermal_capacity",  # CPG 气相比热容 J/kg.℃
        "oil_thermal_capacity",  # CPHL 油相比热容 J/kg.℃
        "water_thermal_capacity",  # CPWT 水相比热容 J/kg.℃
        "gas_enthalpy",  # HG 气相焓值 J/kg
        "oil_enthalpy",  # HHL 油相焓值 J/kg
        "water_enthalpy",  # HWT 水相焓值 J/kg
        "gas_thermal_conductivity",  # TCG 气相导系数 w/m.C
        "oil_thermal_conductivity",  # TCHL 油相导热系数 w/m.C
        "water_thermal_conductivity",  # TCWT 水相导热系数 w/m.C
        "surface_tension_between_gas_and_oil",  # SIGGHL 气油界面张力 N/m
        "surface_tension_between_gas_and_water",  # SIGGWT 气水界面张力 N/m
        "surface_tension_between_oil_and_water",  # SIGHLWT 油水界面张力 N/m
        "gas_entropy",  # SEG 气相熵值 J/kg.k
        "oil_entropy",  # SEHL 油相熵值 J/kg.k
        "water_entropy",  # SEWT 水相熵值 J/kg.k
    ]

    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            result = func(*args, **kwargs)
            dict = {}
            # 初始化dict
            for key in dict_text:
                dict[key] = np.zeros_like(args[0][:, 0])
            if params_indices_in_tabparams is not None:
                # 根据传入的索引获取对应的变量名
                for i, idx in enumerate(params_indices_in_tabparams):
                    dict[dict_text[idx]] = result[i]
            else:
                raise ValueError("tab表中没有对应的变量, 请检查tab文件")
            return dict

        return wrapper

    return decorator